﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using theguineasyndrome.editor.io;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using RawLevelFormat;

namespace theguineasyndrome.editor
{
    public abstract class LevelConverter
    {
        private static Dictionary<Type, RawLevel.ElementType> types = null;

        private static void init()
        {
            if (types == null)
            {
                types = new Dictionary<Type, RawLevel.ElementType>();
                types[typeof(BackgroundElement)] = RawLevel.ElementType.BACKGROUND;
                types[typeof(ForegroundElement)] = RawLevel.ElementType.FOREGROUND;
                types[typeof(ObstacleElement)  ] = RawLevel.ElementType.OBSTACLE;
                types[typeof(PortalableElement)] = RawLevel.ElementType.PORTALABLE;
                types[typeof(SceneryElement)   ] = RawLevel.ElementType.SCENERY;
                types[typeof(BurnableElement)  ] = RawLevel.ElementType.BURNABLE;
            }
        }

        private static RawLevel.ElementType getElementType(Type type)
        {
            return types[type];
        }

        private static Type getClassType(RawLevel.ElementType type)
        {
            Type classType = typeof(BackgroundElement);
            foreach (KeyValuePair<Type, RawLevel.ElementType> kv in types)
            {
                if (kv.Value == type)
                {
                    classType = kv.Key;
                    break;
                }
            }
            return classType;
        }

        public static RawLevel fromLevel(Level level)
        {
            init();

            RawLevel rl = new RawLevel();

            foreach (LevelElement element in level.getElements())
            {
                RawLevel.Element e;
                string textureName = element.getTextureName();
                e.textureId = rl.addTexture(textureName); // add texture!
                e.type = getElementType(element.GetType());
                e.position = element.Position;
                e.name = "";
                rl.addElement(e);
            }

            foreach (KeyValuePair<string, editor.PointMark> kv in level.getPointsMarks())
            {
                RawLevel.PointMark pm;
                pm.name = kv.Key;
                pm.position = kv.Value.getPosition();
                rl.addPointMark(pm);
            }

            return rl;
        }

        public static Level toLevel(RawLevel rawLevel, ContentManager Content)
        {
            init();

            Level level = new Level(Content);

            List<LevelElement> elements = new List<LevelElement>();

            int numTextures = rawLevel.Textures.Count;
            Texture2D[] textures = new Texture2D[numTextures];
            for (int i = 0; i < numTextures; i++)
            {
                textures[i] = Content.Load<Texture2D>(rawLevel.Textures[i]);
                textures[i].Name = rawLevel.Textures[i];
            }

            Texture2D pointMarkTexture = Content.Load<Texture2D>("images/redsquare");
            SpriteFont pointMarkSpriteFont = Content.Load<SpriteFont>("fonts/editor");

            Type[] constructorParams = new Type[] {
                typeof(Level),
                typeof(Texture2D),
                typeof(Vector2)
            };

            foreach (RawLevel.Element element in rawLevel.Elements)
            {
                object[] paramValues = new object[] {
                    level,
                    textures[element.textureId],
                    element.position
                };
                LevelElement le = (LevelElement)getClassType(element.type).GetConstructor(constructorParams).Invoke(paramValues); // invokes the right constructor according to element.type
                elements.Add(le);
            }

            level.paginateElements(elements);

            foreach (RawLevel.PointMark pointMark in rawLevel.PointMarks)
            {
                editor.PointMark pm = new editor.PointMark(pointMarkTexture, pointMarkSpriteFont, pointMark.position);
                pm.setName(pointMark.name);
                level.addPointMark(pm);
            }

            return level;
        }
    }
}
